



#include "SocketMatTransmissionClient.h"

#include <thread.h>
#include <chrono>
#include <sys/time.h>
#include <uart.h>
#include <sys/mman.h>      // 包含POSIX mmap()函数和相关宏定义
#include <fcntl.h>         // 包含open()函数和相关宏定义
#include <time.h>
#include <aio.h>

pthread_t thread[PTHREAD_NUM];

pthread_mutex_t mut;
#define WIDTH 1920
#define HEIGHT 1200
#define PIC_CHANNAL 3

#define MIPI_CAM_IRQ  _IOR('m',1,int)
#define GET_READ_MEM_ID  _IOR('r',1,int)
#define IOCTL_AR0234_EXPOSURE_TIME  _IOW('a',0x1,uint16_t)
#define IOCTL_AR0234_ANALOG_GAIN  _IOW('a',0x2,uint16_t)
#define IOCTL_AR0234_RED_GAIN  _IOW('a',0x3,uint16_t)
#define IOCTL_AR0234_BLUE_GAIN  _IOW('a',0x4,uint16_t)
#define IOCTL_AR0234_GR_GB_GAIN  _IOW('a',0x5,uint16_t)

int thread_Init(void) 
{
  //用默认属性初始化互斥锁
  pthread_mutex_init(&mut, NULL);
  thread_create();
  thread_wait();
  return 0;
}

void thread_create(void)
{
    int temp;
    memset(&thread, 0, sizeof(thread)); //comment1
    //创建线程
    if((temp = pthread_create(&thread[0], NULL, transmit_server, NULL)) != 0) //comment2
        printf("recv_client1 create fail\n");
    else
        printf("recv_client1 create ok\n");
    // if((temp = pthread_create(&thread[1], NULL, recv_server, NULL)) != 0) //comment3
    //     printf("recv_client2 create fail\n");
    // else
    //     printf("recv_client2 create ok\n");

	// if((temp = pthread_create(&thread[2], NULL, uart_recv, NULL)) != 0) //comment4
    //     printf("uart_recv create fail\n");
    // else
    //     printf("uart_recv create ok\n");
}



void thread_wait(void)
{
    //等待线程结束
    if(thread[0] !=0) { //comment
        pthread_join(thread[0], NULL);
        printf("thread0 end\n");
    }
    if(thread[1] !=0) { //comment
        pthread_join(thread[1], NULL);
        printf("thread1 end\n");
    }
	if(thread[2] !=0) { //comment
        pthread_join(thread[2], NULL);
        printf("thread2 end\n");
    }
}

// 计算页对齐后的页面数
unsigned long get_aligned_pages(unsigned long size) {
    return (size + 4096 - 1) / 4096;
}

uint16_t rgb_gain_transfer(float gain){
	// 整数
	uint16_t gain_int = (uint16_t)gain;
	// 小数
	float gain_float = gain - gain_int;
	// 转为0-128区间
	float result = gain_float / 0.0078125;
	// 取低7位
	uint16_t result_int = (uint16_t)result & 0x7F;
	// 组合两个值
	uint16_t combined = (gain_int << 7) | result_int;
	return combined;
}

#define USE_MMAP 0
#define USE_COPY_TO_USER 1
#define USE_AIO 0
#define USE_2BUFFER 0

void *transmit_server(void *ptr)
{
	// 变量定义区域
	int my_cout = 0;
	// 时间戳变量
	clock_t start, mid, end;
	// 图像缓存区
	
	char buf = 1;
	struct pollfd poll_vdma0;
	int image_size = HEIGHT * WIDTH * PIC_CHANNAL;
	
	struct aiocb aiocb; // 异步I/O控制块
	cout<<"transmit_server : I'm thread"<<endl;
	cout<<"height:"<<HEIGHT<<", width:"<<WIDTH<<endl;
	// 申请并初始化图像缓存区
	unsigned char *Lbuf = (unsigned char *)malloc(image_size);
	memset(Lbuf, 0, image_size);
	// 打开设备文件
	int fd = open("/dev/vdma0",O_RDWR);
	cout<<"fd:"<<fd<<endl;
	if(fd<0){
		printf("fd open fail!\r\n");
		cout<<"fd open fail"<<endl;
		return NULL;
	}
	// 映射设备文件到内存
	void *mapped_mem1 = mmap(NULL, image_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (mapped_mem1 == MAP_FAILED) {
		perror("mmap failed");
		close(fd);
		return NULL;
	}
	void *mapped_mem2 = NULL;
	#if USE_2BUFFER == 1
	{
		mapped_mem2 = mmap(NULL, image_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, get_aligned_pages(image_size)*4096);
		if (mapped_mem2 == MAP_FAILED) {
			perror("mmap2 failed");
			close(fd);
			return NULL;
		}
	}
	
	#endif
	// 指针转换
	unsigned char* Rbuf = NULL;
	// 设置poll监测事件
	poll_vdma0.events = POLLIN;
	poll_vdma0.fd = fd;

	// 配置相机
	int cam_fd = open("/dev/ar0234", O_RDWR);
	if(cam_fd<0){
		cout<<"cam_fd open fail"<<endl;
		return NULL;
	}
	float exposure_time = 2;
	uint16_t exposure_time_uint16_t = exposure_time*1000/13.6;
	cout<<"exposure_time_uint16_t:"<<exposure_time_uint16_t<<endl;
	if(ioctl(cam_fd, IOCTL_AR0234_EXPOSURE_TIME, &exposure_time_uint16_t) < 0){
		cout<<"exposure_time set fail"<<endl;
		perror("ioctl");
		return NULL;
	}
	uint16_t analog_gain = 0x016;
	ioctl(cam_fd, IOCTL_AR0234_ANALOG_GAIN, &analog_gain);
	float red_gain = 1.4;
	float blue_gain = 1.5;
	float gr_gb_gain = 1;
	uint16_t red_gain_uint16_t = rgb_gain_transfer(red_gain);
	cout<<"red_gain_uint16_t:"<<red_gain_uint16_t<<endl;
	uint16_t blue_gain_uint16_t = rgb_gain_transfer(blue_gain);
	cout<<"blue_gain_uint16_t:"<<blue_gain_uint16_t<<endl;
	uint16_t gr_gb_gain_uint16_t = rgb_gain_transfer(gr_gb_gain);
	cout<<"gr_gb_gain_uint16_t:"<<gr_gb_gain_uint16_t<<endl;

	if(ioctl(cam_fd, IOCTL_AR0234_RED_GAIN, &red_gain_uint16_t) < 0){
		cout<<"red_gain set fail"<<endl;
	}
	ioctl(cam_fd, IOCTL_AR0234_BLUE_GAIN, &blue_gain_uint16_t);
	ioctl(cam_fd, IOCTL_AR0234_GR_GB_GAIN, &gr_gb_gain_uint16_t);
	while(1)
	{
		#if USE_2BUFFER == 1
		{
			my_cout++;
			int ret = poll(&poll_vdma0, 1, -1);
			if (ret < 0){
				printf("error\n");
			}
			int read_mem_id = 0;
			ioctl(fd, GET_READ_MEM_ID, &read_mem_id);
			cout<<"read_mem_id:"<<read_mem_id<<endl;
			if (read_mem_id == 0) {
				Rbuf = (unsigned char*)mapped_mem1;
			} else {
				Rbuf = (unsigned char*)mapped_mem2;
			}
			cout<<"step1 USE_2BUFFER mode"<<endl;
			// 开始计时
			string file_name = "image"+std::to_string(my_cout)+".raw";
			start = clock();
			int file_fd = open(file_name.data(), O_WRONLY | O_CREAT);
			if (file_fd < 0) {
				perror("Unable to open file");
				return NULL;
			}
			if (fallocate(file_fd, 0, 0, image_size) == -1) {
				perror("Failed to allocate space");
				close(file_fd);
				return NULL;
			}
			
			cout<<"step2"<<endl;
			mid = clock();
			// 写入图片数据
			size_t written = write(file_fd, Rbuf, image_size);
			if (written != image_size) {
				perror("Failed to write the entire image data");
				close(file_fd);
				return NULL;
			}
			// 关闭文件
			close(file_fd);
			
			end = clock();

		}
		 	
		#elif USE_MMAP == 1
		{
			my_cout++;
			cout<<"step0"<<endl;
			// 等待100ms一次的相机中断到来
			ioctl(fd, MIPI_CAM_IRQ, 1);
			// 提交vdma传输任务
			write(fd, &buf, 1);
			// 开始poll监测，等待传输完成
			int ret = poll(&poll_vdma0, 1, -1);
			if (ret < 0){
				printf("error\n");
			}
			cout<<"step1 USE_MMAP mode"<<endl;
			// 开始计时
			string file_name = "image"+std::to_string(my_cout)+".raw";
			start = clock();
			int file_fd = open(file_name.data(), O_WRONLY | O_CREAT);
			if (file_fd < 0) {
				perror("Unable to open file");
				return NULL;
			}
			if (fallocate(file_fd, 0, 0, image_size) == -1) {
				perror("Failed to allocate space");
				close(file_fd);
				return NULL;
			}
			
			cout<<"step2"<<endl;
			mid = clock();
			// 写入图片数据
			size_t written = write(file_fd, mapped_mem1, image_size);
			if (written != image_size) {
				perror("Failed to write the entire image data");
				close(file_fd);
				return NULL;
			}
			// 关闭文件
			close(file_fd);
			end = clock();
		}
		#elif USE_COPY_TO_USER == 1
		{
			my_cout++;
			cout<<"step0"<<endl;
			// 等待100ms一次的相机中断到来
			ioctl(fd, MIPI_CAM_IRQ, 1);
			// 提交vdma传输任务
			write(fd, &buf, 1);
			// 开始poll监测，等待传输完成
			int ret = poll(&poll_vdma0, 1, -1);
			if (ret < 0){
				printf("error\n");
			}
			cout<<"step1 USE_COPY_TO_USER mode"<<endl;
		 // 开始计时
			start = clock();
			// 使用copy_to_user将数据从设备文件拷贝到缓存区
			read(fd, Lbuf, image_size);
			mid = clock();
			cout<<"step2"<<endl;
			Mat buffer2(HEIGHT, WIDTH, CV_8UC3, Lbuf);
			string file_name = "output_image"+std::to_string(my_cout)+".bmp";
			// string file_name = "output_image.bmp";
			if(my_cout >= 30){ my_cout = 0;}	
			bool isSaved = cv::imwrite(file_name, buffer2);
			// 检查图像是否保存成功
			if(!isSaved) {
				std::cout << "Failed to save the image" << std::endl;
				return NULL;
			}
			
			// 传输图片数据
			cv::Mat topLeftCorner = buffer2(cv::Rect(0, 0, 1000, 800));
			SocketMat.Transmit_Server(topLeftCorner);
			end = clock();
		}
		#elif USE_AIO == 1
		{
			my_cout++;
			cout<<"step0"<<endl;
			// 等待100ms一次的相机中断到来
			ioctl(fd, MIPI_CAM_IRQ, 1);
			// 提交vdma传输任务
			write(fd, &buf, 1);
			// 开始poll监测，等待传输完成
			int ret = poll(&poll_vdma0, 1, -1);
			if (ret < 0){
				printf("error\n");
			}
			cout<<"step1 USE_AIO mode"<<endl;
		 // 开始计时
			start = clock();
			string file_name = "image"+std::to_string(my_cout)+".raw";
			start = clock();
			int file_fd = open(file_name.data(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
			// 初始化异步I/O控制块
			memset(&aiocb, 0, sizeof(aiocb));
			aiocb.aio_fildes = file_fd;
			aiocb.aio_buf = mapped_mem1;
			aiocb.aio_nbytes = image_size;
			aiocb.aio_offset = 0;
			// 发起异步写操作
			if (aio_write(&aiocb) == -1) {
				perror("aio_write");
				close(fd);
				munmap(mapped_mem1, image_size);
				return NULL;
			}
			mid = clock();
			// 等待异步写操作完成
			struct aiocb *list[] = { &aiocb };
			if (aio_suspend(list, 1, NULL) == -1) {
				perror("aio_waitcomplete");
			}
			// 清理资源
			close(file_fd);
			end = clock();
		}
		#endif

		// SocketMat.Transmit_Server(buffer2);//传输
		cout<<"step3,saved No. "<<my_cout<<" pic"<<endl;
		double cpu_time_used_mid = ((double) (mid - start)) / CLOCKS_PER_SEC;
		double cpu_time_used = ((double) (end - mid)) / CLOCKS_PER_SEC;
		cout<<"mid-start use "<<cpu_time_used_mid<<endl;
		cout<<"end-mid use "<<cpu_time_used<<endl;
		cout<<endl;

	}
//
	// while(1)
	// {
	//   //接收发来的消息   
	//   //puts("waiting data ......");    
    // 	   SocketMat.Transmit_Server_2();
	// }	
	munmap(mapped_mem1, image_size);
    pthread_exit(NULL);
}

 
void *recv_server(void *ptr)
{
    printf("recv_server : I'm thread\n");  
	while(1)
	{
	//接收发来的消息   
	//puts("waiting data ......");    
    	SocketMat.Recv_Server();
	}
    pthread_exit(NULL);
}
void *uart_recv(void *ptr)
{
	printf("uart_recv : I'm thread\n");  
	while(1)
	{
    	//SocketMat.Recv_Server();
		//Uart0.Recv();
	}
	//Uart0.Uart_Close();
    pthread_exit(NULL);
}

















